package fr.generali.accueilclient.gwt.client.activity;

import java.util.HashMap;
import java.util.Map;

import javax.inject.Provider;

import com.google.gwt.activity.shared.Activity;
import com.google.gwt.activity.shared.ActivityMapper;
import com.google.gwt.inject.client.AsyncProvider;
import com.google.gwt.place.shared.Place;

import fr.generali.accueilclient.gwt.client.common.ExceptionHandler;

public class PlaceActivityMapper implements ActivityMapper {

    private final ExceptionHandler exceptionHandler;

    public PlaceActivityMapper(ExceptionHandler exceptionHandler) {
        this.exceptionHandler = exceptionHandler;
    }

    private final Map<Class< ? extends Place>, PlaceActivityMapping< ? extends PlaceActivity< ? >, ? extends Place>> mappers =
                    new HashMap<Class< ? extends Place>, PlaceActivityMapping< ? extends PlaceActivity< ? >, ? extends Place>>();

    @Override
    public Activity getActivity(Place place) {
        return getPlaceActivity(place);
    }
    

    private <P extends Place, A extends PlaceActivity<P>> ActivityProxy<A> getPlaceActivity(P place) {

        @SuppressWarnings("unchecked")
        PlaceActivityMapping<A, P> mapper = (PlaceActivityMapping<A, P> ) mappers.get(place.getClass());

        ActivityProxy<A> activity = mapper.getActivity(place);

        return activity;
    }

    protected <P extends Place, A extends PlaceActivity<P>> void register(Class<P> clazz,
                    PlaceActivityMapping<A, P> mapper) {

        if (mappers.get(clazz) != null)
            throw new IllegalStateException("Place : " + clazz.getName() + "already registered");
        
        mappers.put(clazz, mapper);
    }

    protected <P extends Place, A extends PlaceActivity<P>> void register(Class<P> clazz, AsyncProvider<A> provider) {
        register(clazz, new AsyncPlaceActivityMapping<A, P>(provider, exceptionHandler));
    }

    protected <P extends Place, A extends PlaceActivity<P>> void register(Class<P> clazz, AsyncProvider<A> provider,
                    ExceptionHandler exceptionHandler) {
        register(clazz, new AsyncPlaceActivityMapping<A, P>(provider, exceptionHandler));
    }

    protected <P extends Place, A extends PlaceActivity<P>> void register(Class<P> clazz, Provider<A> provider) {
        register(clazz, new DirectPlaceActivityMapping<A, P>(provider));
    }
}
